Support Unicode environment variables.
authorViet-Tam Luu <viettaml@google.com>
Fri, 1 Dec 2017 00:53:58 +0000 (16:53 -0800)
committerViet-Tam Luu <viettaml@google.com>
Fri, 1 Dec 2017 00:53:58 +0000 (16:53 -0800)
Create ugetenv() OS-abstraction to return a QString environment variable value. Use it in place of getenv() in most places. Update inifile.cc routines to use QString to support Unicode paths for the gpsbabel.ini file, also greatly streamlining the code.

csv_util.cc
defs.h
html.cc
inifile.cc
util.cc

index 0cc8a9a4f63387674e92abb8580053c39d7b261f..2f42e50125a5804ede91889cad9e39904a5a7a7f 100644 (file)
@@ -1215,11 +1215,11 @@ xcsv_parse_val(const char* s, Waypoint* wpt, const field_map_t* fmp,
     wpt->SetCreationTime(sscanftime(s, fmp->printfc, 1));
     break;
   case XT_LOCAL_TIME:
-    if (getenv("GPSBABEL_FREEZE_TIME")) {
+    if (ugetenv("GPSBABEL_FREEZE_TIME").isNull()) {
+      wpt->creation_time += sscanftime(s, fmp->printfc, 0);
+    } else {
       /* Force constant time zone for test */
       wpt->creation_time += sscanftime(s, fmp->printfc, 1);
-    } else {
-      wpt->creation_time += sscanftime(s, fmp->printfc, 0);
     }
     break;
     /* Useful when time and date are in separate fields
diff --git a/defs.h b/defs.h
index 0d57241b19d891cfe3b8748921321de1d8dba2a1..eec287d1f92a4ba3d7fd0ab8b7f4f96e9ac58718 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -931,6 +931,9 @@ void debug_mem_close();
 
 FILE* xfopen(const char* fname, const char* type, const char* errtxt);
 
+// OS-abstracting wrapper for getting Unicode environment variables.
+QString ugetenv(const char* env_var);
+
 // FIXME: case_ignore_strcmp() and case_ignore_strncmp() should probably
 // just be replaced at the call sites.  These shims are just here to make
 // them more accomidating of QString input.
diff --git a/html.cc b/html.cc
index 6f8b2770e1121b3e20eeebed29b030cf7a5e09d1..4ae4467f8588a25d940ac96eaeec3c42e59bbab2 100644 (file)
--- a/html.cc
+++ b/html.cc
@@ -260,7 +260,7 @@ data_write()
 
   // Don't write this line when running test suite.  Actually, we should
   // probably not write this line at all...
-  if (!getenv("GPSBABEL_FREEZE_TIME")) {
+  if (ugetenv("GPSBABEL_FREEZE_TIME").isNull()) {
     gbfprintf(file_out, " <meta name=\"Generator\" content=\"GPSBabel %s\">\n", gpsbabel_version);
   }
   gbfprintf(file_out, " <title>GPSBabel HTML Output</title>\n");
index aa5e8b00096d049a6d9ab999f173085a53e0a789..78b18241039e6366fb63d016fef2a6474599ca37 100644 (file)
@@ -20,6 +20,8 @@
 
 #include "defs.h"
 #include "inifile.h"
+#include <QtCore/QDir>
+#include <QtCore/QFile>
 #include <cstdio>
 #include <cstdlib>
 
@@ -44,98 +46,55 @@ typedef struct inifile_section_s {
 #define DELTA_BUFSIZE 128
 
 #define GPSBABEL_INIFILE "gpsbabel.ini"
+#define GPSBABEL_SUBDIR ".gpsbabel"
 
 /* Remember the filename we used so we can include it in errors. */
-char* gbinipathname;
+QString gbinipathname;
 
-static char*
-find_gpsbabel_inifile(const char* path)                /* can be empty or NULL */
+static QString
+find_gpsbabel_inifile(const QString& path)  /* can be empty or NULL */
 {
-  FILE* test;
-  char* buff;
-  int len;
-
-  if (path == NULL) {
-    return NULL;
-  }
-
-  len = strlen(path);
-  buff = (char*) xmalloc(len + 1 + strlen(GPSBABEL_INIFILE) + 1);
-  strcpy(buff, path);
-  if (len > 0) {
-    char test = buff[len - 1];
-#ifdef __WIN32__
-    if ((test != '\\') && (test != ':')) {
-      strcat(buff, "\\");
-    }
-#else
-    if (test != '/') {
-      strcat(buff, "/");
-    }
-#endif
-  }
-  strcat(buff, GPSBABEL_INIFILE);
-  test = fopen(buff, "rb");
-  if (test) {
-    fclose(test);
-    return buff;
+  if (path.isNull()) {
+    return QString();
   }
-  xfree(buff);
-  return NULL;
+  QString inipath(QDir(path).filePath(GPSBABEL_INIFILE));
+  return QFile(inipath).open(QIODevice::ReadOnly) ? inipath : QString();
 }
 
 static gbfile*
 open_gpsbabel_inifile()
 {
-  char* name;
-  char* envstr;
+  QString name;
+  QString envstr;
   gbfile* res = NULL;
 
-  envstr = getenv("GPSBABELINI");
-  if (envstr != NULL) {
-    FILE* test;
-
-    test = fopen(envstr, "r");
-    if (test != NULL) {
-      fclose(test);
+  envstr = ugetenv("GPSBABELINI");
+  if (!envstr.isNull()) {
+    if (QFile(envstr).open(QIODevice::ReadOnly)) {
       return gbfopen(envstr, "r", "GPSBabel");
     }
     warning("WARNING: GPSBabel-inifile, defined in environment, NOT found!\n");
     return NULL;
   }
-  name = find_gpsbabel_inifile("");    /* PWD */
-  if (name == NULL) {
+  name = find_gpsbabel_inifile("");  // Check in current directory first.
+  if (name.isNull()) {
 #ifdef __WIN32__
-    name = find_gpsbabel_inifile(getenv("APPDATA"));
-    if (name == NULL) {
-      name = find_gpsbabel_inifile(getenv("WINDIR"));
-    }
-    if (name == NULL) {
-      name = find_gpsbabel_inifile(getenv("SYSTEMROOT"));
-    }
+    // Use &&'s early-out behaviour to try successive file locations: first
+    // %APPDATA%, then %WINDIR%, then %SYSTEMROOT%.
+    (name = find_gpsbabel_inifile(ugetenv("APPDATA"))).isNull()
+        && (name = find_gpsbabel_inifile(ugetenv("WINDIR"))).isNull()
+        && (name = find_gpsbabel_inifile(ugetenv("SYSTEMROOT"))).isNull();
 #else
-    if ((envstr = getenv("HOME")) != NULL) {
-      char* path;
-
-      path = (char*) xmalloc(strlen(envstr) + 11);
-      strcpy(path, envstr);
-      strcat(path, "/.gpsbabel");
-      name = find_gpsbabel_inifile(path);
-      xfree(path);
-    }
-    if (name == NULL) {
-      name = find_gpsbabel_inifile("/usr/local/etc");
-    }
-    if (name == NULL) {
-      name = find_gpsbabel_inifile("/etc");
-    }
+    // Use &&'s early-out behaviour to try successive file locations: first
+    // ~/.gpsbabel, then /usr/local/etc, then /etc.
+    (name = find_gpsbabel_inifile(QDir::home().filePath(GPSBABEL_SUBDIR))).
+            isNull()
+        && (name = find_gpsbabel_inifile("/usr/local/etc")).isNull()
+        && (name = find_gpsbabel_inifile("/etc")).isNull();
 #endif
   }
-  if (name != NULL) {
+  if (!name.isNull()) {
     res = gbfopen(name, "r", "GPSBabel");
-    if (gbinipathname) {
-      xfree(gbinipathname);
-    }
     gbinipathname = name;
   }
   return res;
@@ -171,7 +130,8 @@ inifile_load_file(gbfile* fin, inifile_t* inifile, const char* myname)
         cin = lrtrim(cin);
       }
       if ((*cin == '\0') || (cend == NULL)) {
-        fatal("%s: invalid section header '%s' in '%s'.\n", myname, cin, gbinipathname);
+        fatal("%s: invalid section header '%s' in '%s'.\n", myname, cin,
+              qPrintable(gbinipathname));
       }
 
       sec = (inifile_section_t*) xcalloc(1, sizeof(*sec));
@@ -185,7 +145,8 @@ inifile_load_file(gbfile* fin, inifile_t* inifile, const char* myname)
       inifile_entry_t* entry;
 
       if (sec == NULL) {
-        fatal("%s: missing section header in '%s'.\n", myname,gbinipathname);
+        fatal("%s: missing section header in '%s'.\n", myname,
+              qPrintable(gbinipathname));
       }
 
       entry = (inifile_entry_t*) xcalloc(1, sizeof(*entry));
@@ -306,10 +267,7 @@ inifile_done(inifile_t* inifile)
     }
     xfree(inifile);
   }
-  if (gbinipathname) {
-    xfree(gbinipathname);
-    gbinipathname = NULL;
-  }
+  gbinipathname.clear();
 }
 
 int
diff --git a/util.cc b/util.cc
index 67a300ae0fdbb480c78539f819c853110e4a0172..fd567371abeb87da0ed859e12ae0fe4c48e5c6a4 100644 (file)
--- a/util.cc
+++ b/util.cc
@@ -258,6 +258,19 @@ xfopen(const char* fname, const char* type, const char* errtxt)
   return f;
 }
 
+/*
+ * OS-abstracting wrapper for getting Unicode environment variables.
+ */
+QString ugetenv(const char* env_var) {
+#ifdef __WIN32__
+  // Use QString to convert 8-bit env_var argument to wchar_t* for _wgetenv().
+  return QString::fromWCharArray(
+      _wgetenv((const wchar_t*) QString(env_var).utf16()));
+#else
+  // Everyone else uses UTF-8 or some other locale-specific 8-bit encoding.
+  return QString::fromLocal8Bit(std::getenv(env_var));
+#endif
+}
 /*
  * Allocate a string using a format list with optional arguments
  * Returns -1 on error.